home *** CD-ROM | disk | FTP | other *** search
- /*
- CMD_C - command interpreter for QL-Kermit
-
- Based on ckucmd.c, (C) Columbia University
- */
-
-
- /* Include files */
-
- #include "flp1_ctype_h" /* Character types */
-
- #include "ram1_ker_h" /* Kermit definitions */
- #include "ram1_cmd_h" /* Command parser definitions */
-
-
- /* External variables */
-
- extern char cmdbuf[]; /* Command buffer */
-
-
- /* Local variables */
-
- #define PROML 60 /* Maximum prompt length */
-
- char cmprom[PROML+2]; /* Prompt string */
-
- int cc = 0; /* Character count */
- int cmflgs; /* Command flags */
-
- char *dfprom = "Kermit> "; /* Default prompt */
-
- char atmbuf[ATMBL+4]; /* Atom buffer */
- char filbuf[ATMBL+4]; /* File name buffer */
-
- static bool psetf = FALSE; /* Prompt set flag */
-
- static char *bp; /* Command buffer position */
- static char *pp; /* Start of current field */
- static char *np; /* Start of next field */
-
-
-
- /* CMSETP - Set the program prompt */
-
- cmsetp(s)
- char *s;
- {
- char *strncpy();
-
- psetf = TRUE; /* Flag that prompt is set */
- strncpy(cmprom,s,PROML-1); /* Copy the string */
- cmprom[PROML] = NUL; /* Ensure null terminator */
- }
-
-
- /* PROMPT - Issue the program prompt */
-
- prompt()
- {
- if (!psetf) cmsetp(dfprom); /* If not set, use default */
- printf("%s",cmprom); /* Print the prompt */
- }
-
-
- /* CMRES - Reset pointers to beginning of command buffer */
-
- cmres()
- {
- cc = 0; /* Reset character counter */
- pp = np = bp = cmdbuf; /* Point to command buffer */
- cmflgs = -5; /* Parse not yet started */
- }
-
-
- /* CMINI - Clear the command and atom buffers, reset pointers */
-
- cmini()
- {
- for (bp = cmdbuf; bp<cmdbuf+CMDBL; bp++) *bp = NUL;
- *atmbuf = NUL;
- cmres();
- }
-
-
- /* CMNUM - Parse a numeric field
-
- Returns:
- -3 if no input present when required,
- -2 if user typed an illegal number,
- -1 if reparse needed,
- 0 otherwise, with *n set to number that was parsed
- */
-
- int cmnum(xdef,n,xhlp)
- char *xdef;
- int *n;
- char *xhlp;
- {
- char *s;
- int x;
-
- x = cmfld(xdef,&s,xhlp);
- if (x<0) return(x); /* Parse the field */
-
- if (digits(atmbuf)) /* Check for valid number */
- {
- *n = atoi(atmbuf); /* and convert field */
- return(x);
- }
- else
- {
- error("Not a number - %s",s);
- return(-2);
- }
- }
-
-
- /* CMFLD - Parse an arbitrary field
-
- Returns:
- -3 if no input present when required,
- -2 if field too big for buffer,
- -1 if reparse needed,
- 0 otherwise, xp pointing to string result
- */
-
- int cmfld(xdef,xp,xhlp)
- char *xdef;
- char **xp;
- char *xhlp;
- {
- int x,xc;
-
- cc = xc = 0; /* Initialize counts & pointers */
- *xp = "";
- if ((x = cmflgs)!=1) x = getwd(); /* Get a word if required */
- else cc = setatm(xdef); /* or use default, if any */
- *xp = atmbuf; /* Point to result */
-
- forever
- {
- xc += cc; /* Count the characters */
- switch (x)
- {
- case -4: /* EOF */
- case -2: /* Out of space */
- case -1: return(x); /* Reparse needed */
-
- case 0: /* SP or NL */
- case 1: if (xc==0) *xp = xdef; /* If no input, return default */
- else *xp = atmbuf;
- if (**xp==NUL) x = -3; /* If field empty, return -3 */
- return(x);
-
- case 2: if (xc==0) /* ESC */
- { /* If at beginning of field, */
- printf("%s ",xdef);
- addbuf(xdef); /* supply default */
- cc = setatm(xdef); /* Return as if whole field */
- return(0); /* typed, followed by space */
- }
- endcase;
-
- case 3: if (xc==0) /* Question mark */
- { /* If at beginning of field, */
- help(xhlp,"Complete this field");
- endcase; /* Retype and continue */
- }
- }
- x = getwd();
- }
- }
-
-
- /* CMTXT - Get a text string, including confirmation
-
- Supply default 'xdef' if null string typed
- Returns:
- -1 if reparse needed or buffer overflows
- 1 otherwise, with cmflgs = return code,
- **xp = result string.
- */
-
- int cmtxt(xdef,xp,xhlp)
- char *xdef;
- char **xp;
- char *xhlp;
- {
- int x;
- static int xc;
-
- cc = 0; /* Start atmbuf counter off */
- if (cmflgs==-1) /* If reparsing, */
- {
- xc = strlen(*xp); /* get back total text length, */
- }
- else
- { /* otherwise */
- *xp = ""; /* start afresh */
- xc = 0;
- }
- *atmbuf = NUL; /* Empty atom buffer */
-
- if ((x = cmflgs)!=1)
- {
- x = getwd(); /* Get first word */
- *xp = pp; /* Save pointer to it */
- }
-
- forever
- {
- xc += cc; /* Char count for all words */
- switch (x)
- {
- case -4: /* EOF */
- case -2: /* Overflow */
- case -1: return(x); /* Reparse needed */
-
- case 0: xc++; /* Space, just count it */
- endcase;
-
- case 1: if (xc==0) *xp = xdef; /* CR or LF */
- return(x);
-
- case 2: if (xc==0) /* ESC */
- {
- printf("%s ",xdef); /* If at start, use default */
- cc = addbuf(xdef);
- }
- endcase;
-
- case 3: if (xc==0) /* Question mark */
- {
- help(xhlp,"Text string");
- endcase;
- }
- }
- x = getwd();
- }
- }
-
-
- /* CMKEY - Parse a keyword
-
- Call with:
- *table = keyword table, in 'struct keytab' format,
- n = number of entries in table,
- *xdef = default keyword;
-
- Returns:
- -3 if no input supplied and no default available
- -2 if input doesn't uniquely match a keyword in the table
- -1 if user deleted too much, command reparse required
- or value associated with keyword
- */
-
- int cmkey(table,n,xdef,xhlp)
- struct keytab table[];
- int n;
- char *xdef,*xhlp;
- {
- int y,z,zz,xc,i,j;
- char *xp;
-
- xc = cc = 0; /* Clear character counters */
- if ((zz = cmflgs)==1) setatm(xdef); /* Command already entered? */
- else zz = getwd();
-
- forever
- {
- xc += cc;
- switch(zz)
- {
- case -4: /* EOF */
- case -2: /* Overflow */
- case -1: return(zz); /* Reparse needed */
-
- case 0: /* Word terminated with space */
- case 1: if (cc==0) setatm(xdef); /* or newline */
- y = lookup(table,atmbuf,n,&z);
- switch (y)
- {
- case -2: if (zz==0) printf("\n");
- error("Ambiguous command or parameter - %s",atmbuf);
- return(cmflgs = -2);
-
- case -1: if (zz==0) printf("\n");
- error("Unknown command or parameter - %s",atmbuf);
- return(cmflgs = -2);
-
- default: endcase;
- }
- return(y);
-
- case 2: if (cc==0) /* Word terminated with ESC */
- {
- if (*xdef!=NUL) /* If at start, */
- {
- printf("%s ",xdef); /* supply default if any */
- addbuf(xdef);
- cc = setatm(xdef);
- }
- else endcase;
- }
-
- y = lookup(table,atmbuf,n,&z); /* Something in atmbuf */
- if (y==-2) endcase; /* Ambiguous */
- if (y==-1) /* Not found */
- {
- error("Unknown command or parameter - %s",atmbuf);
- return(cmflgs = -2);
- }
-
- xp = table[z].kwd+cc;
- printf("%s ",xp);
- addbuf(xp);
- return(y);
-
- case 3: if (cc==0) /* Question mark */
- { /* If at start of field, */
- printf("?");
- if (xhlp==NULL) printf("\nHELP: One of the following -");
- else printf("\nHELP: %s, one of the following -",xhlp);
- for (i = 0, j = 0; i<n; i++) /* dump table */
- if (!test(table[i].flgs,CM_INV))
- printf("%c %-17s",(((j++%2)==0) ? '\n' : ' '),table[i].kwd);
- printf("\n%s%s",cmprom,cmdbuf);
- endcase;
- }
- }
- zz = getwd();
- }
- }
-
-
- /* CMCFM - Parse command confirmation (end of line)
-
- Returns:
- -2 if user typed anything but whitespace or newline
- -1 if reparse needed
- 0 if confirmation was received
- */
-
- int cmcfm()
- {
- int x,xc;
-
- xc = cc = 0;
- if (cmflgs==1) return(0); /* Unnecessary if already entered */
-
- forever
- {
- x = getwd();
- xc += cc;
- switch (x)
- {
- case -4: /* EOF */
- case -2: /* Overflow */
- case -1: return(x); /* Reparse needed */
-
- case 0: continue; /* SP */
-
- case 1: if (xc>0) /* End of line */
- {
- error("Not confirmed - %s",atmbuf);
- return(-2);
- }
- else return(0);
-
- case 2: continue; /* ESC */
-
- case 3: if (xc>0) /* Question mark */
- {
- error("Not confirmed - %s",atmbuf);
- return(-2);
- }
- help("Type ENTER to confirm",NULL);
- continue;
- }
- }
- }
-
-
- /* LOOKUP - Lookup the string in the given array of strings
-
- Call with:
- table = a 'struct keytab' table
- word = the target string to look up in the table
- n = the number of elements in the table
- *x = an integer for returning the table array index
-
- The keyword table must be arranged in ascending alphabetical order,
- and all letters must be lowercase.
-
- Returns the keyword's associated value (zero or greater) if found,
- with the variable x set to the array index, or:
- -3 if nothing to look up (target was null),
- -2 if ambiguous,
- -1 if not found.
-
- A match is successful if the target matches a keyword exactly, or if
- the target is a prefix of exactly one keyword. It is ambiguous if
- the target matches two or more keywords from the table.
- */
-
- int lookup(table,cmd,n,x)
- struct keytab table[];
- char *cmd;
- int n;
- int *x;
- {
- int i,v,cmdlen;
-
- /* Lowercase & get length of target, if it's null return code -3 */
-
- if ((((cmdlen = lower(cmd)))==0) || (n<1)) return(-3);
-
- /* Not null, look it up */
-
- for (i = 0; i<n-1; i++)
- {
- if (!strcmp(table[i].kwd,cmd) ||
- ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
- strncmp(table[i+1].kwd,cmd,cmdlen)))
- {
- *x = i;
- return(table[i].val);
- }
- if (v) return(-2);
- }
-
- /* Last (or only) element */
-
- if (!strncmp(table[n-1].kwd,cmd,cmdlen))
- {
- *x = n-1;
- return(table[n-1].val);
- }
- else return(-1);
- }
-
-
- /* GETWD - Gets a "word" from the command input stream
-
- Returns:
- -4 if end of file (e.g. pipe broken)
- -2 if command buffer overflows
- -1 if user did some deleting
- 0 if word terminates with SP or TAB
- 1 if .. .. .. CR
- 2 if .. .. .. ESC
- 3 if .. .. .. ?
-
- With:
- pp pointing to beginning of word in buffer
- bp pointing to after current position
- atmbuf containing a copy of the word
- cc containing the number of characters in the word copied to atmbuf
- */
-
- int getwd()
- {
- unsigned char c; /* Current character */
- bool echof = FALSE; /* Flag for screen echo */
- static bool inword = FALSE; /* Flag for start of word */
-
- pp = np; /* Start of current field */
-
- while (bp<cmdbuf+CMDBL)
- {
- echof = FALSE;
- if ((c = *bp)==NUL) /* No more in buffer */
- { /* Get next input character */
- echof = TRUE; /* Let's see this on screen */
- c = getch();
- }
-
- if (c==FF) c = LF; /* Replace formfeed with newline, */
- if (c==CR) c = LF; /* carriage return with newline, */
- if (c==HT) c = SP; /* and tab with space */
-
- if (c==SP) /* If space */
- {
- *bp++ = c; /* deposit it in buffer */
- if (echof) putch(c); /* echo it */
- if (!inword) /* If leading, gobble it */
- {
- pp++;
- continue;
- }
- else /* If terminating, return */
- {
- np = bp;
- setatm(pp);
- inword = FALSE;
- return(cmflgs = 0);
- }
- }
-
- if (c==LF) /* End of line */
- {
- *bp = NUL; /* End the string */
- if (echof) putch(c); /* and echo the typein */
- np = bp; /* Where to start next field */
- setatm(pp); /* Copy this field to atom buffer */
- inword = FALSE;
- return(cmflgs = 1);
- }
-
- if (c==F1) /* Help trigger */
- {
- *bp = NUL;
- setatm(pp);
- return(cmflgs = 3);
- }
-
- if (c==ESC || c==F4) /* Complete the field */
- {
- *bp = NUL;
- setatm(pp);
- return(cmflgs = 2);
- }
-
- if (c==DEL || c==F5 || c==DELC) /* Character delete */
- {
- echof = FALSE;
- if (bp>cmdbuf) /* If still in buffer, */
- {
- delch(); /* erase character from screen, */
- bp--; /* point behind it, */
- if (*bp==SP) inword = FALSE; /* Flag if current field gone */
- *bp = NUL; /* Erase character from buffer */
- }
- else cmres(); /* If all gone, start again */
-
- if (pp<=bp) continue;
- else return(cmflgs = -1);
- }
-
- if (c==LDEL || c==F3) /* Line delete */
- {
- while ((bp--)>cmdbuf)
- {
- delch(); /* Run back to beginning */
- *bp = NUL;
- }
- cmres(); /* Restart the command */
- inword = FALSE;
- return(cmflgs = -1);
- }
-
- if (c==RDIS) /* Redisplay */
- {
- *bp = NUL;
- printf("\n%s%s",cmprom,cmdbuf);
- continue;
- }
-
- if (echof) putch(c); /* If tty input, echo */
- inword = TRUE; /* Flag we're in a word */
- if (c!=LF) *bp++ = c; /* and deposit it */
- }
-
- /* Get here if buffer full */
-
- error("Buffer full");
- return(cmflgs = -2);
- }
-
-
- /* ADDBUF - Add the string *cp to the command buffer */
-
- int addbuf(cp)
- char *cp;
- {
- int len = 0;
-
- while ((*cp!=NUL) && (bp<cmdbuf+CMDBL))
- {
- *bp++ = *cp++; /* Copy and */
- len++; /* count the characters */
- }
- *bp++ = SP; /* Put a space at the end */
- *bp = NUL; /* Terminate with a null */
- np = bp; /* Update the next-field pointer */
- return(len); /* Return the length */
- }
-
-
- /* SETATM - Deposit a string in the atom buffer */
-
- int setatm(cp)
- char *cp;
- {
- char *ap;
-
- cc = 0;
- ap = atmbuf;
- *ap = NUL;
- while (*cp==SP) cp++;
- while ((*cp!=SP) && (*cp!=LF) && (*cp!=NUL) && (*cp!=CR))
- {
- *ap++ = *cp++;
- cc++;
- }
- *ap++ = NUL;
- return(cc); /* Return length */
- }
-
-
- /* DIGITS - Verify that all the characters in s are digits */
-
- bool digits(s)
- char *s;
- {
- while (*s!=0) if (!isdigit(*s++)) return(FALSE);
- return(TRUE);
- }
-
-
- /* LOWER - Lowercase a string, return length */
-
- int lower(s)
- char *s;
- {
- int n = 0;
-
- while (*s!=0)
- {
- if (isupper(*s)) *s = tolower(*s);
- s++, n++;
- }
- return(n);
- }
-
-
- /* TEST - Bit test, test whether any bits from m are on in x */
-
- bool test(x,m)
- int x,m;
- {
- return((x&m)!=0);
- }
-
-
- /* HELP - Print the help text string, and replay line */
-
- help(xhlp,null)
- char *xhlp,*null;
- {
- printf("?");
- printf("\nHELP: %s",((xhlp!=NULL) ? xhlp : null));
- printf("\n%s%s",cmprom,cmdbuf);
- }
-